嗨,第24天,接續昨天的主題,我們來要實做隨機代理,將昨天爬到的代理在spider
內使用,隨機代理的話每次對網頁的請求就會被不同的代理分攤,就不容易被封鎖了。
在Scrapy
中,有一個Downloader Middleware
: HttpProxyMiddleware
,是用來給爬蟲設定代理的。
原始程式碼:scrapy/httpproxy.py GitHub
_get_proxy
方法為解析代理資訊,傳回身份驗證的資訊creds
以及代理伺服器url。process_request
方法用來處理每個發送的請求,判斷式if 'proxy' in request.meta
也就是meta
中不包含proxy
欄位(沒設定代理)的請求則呼叫self._set_proxy()
_set_proxy
為請求設定代理,以HTTP
或HTTPS
為key,從self.proxies
中選擇代理指定給request.meta
的proxy
欄位。現在我們基於HttpProxyMiddleware
來實現隨機代理的Middleware
,開啟middlewares.py
:
from scrapy import signals
from scrapy.downloadermiddlewares.httpproxy import HttpProxyMiddleware
from collections import defaultdict
import json
import random
RandomProxyMiddleware
類別且它繼承HttpProxyMiddleware
:class RandomProxyMiddleware(HttpProxyMiddleware):
...
proxies
內: def __init__(self, auth_encoding="latin-1", proxy_list_file=None):
if not proxy_list_file:
raise NotConfigured
self.auth_encoding = auth_encoding
self.proxies = defaultdict(list)
with open(proxy_list_file) as f:
proxy_list = json.load(f)
for proxy in proxy_list:
scheme = proxy["scheme"]
url = proxy["proxy"]
self.proxies[scheme].append(self._get_proxy(url, scheme))
from_crawler
用來讀取settings.py
檔案的參數HTTPPROXY_AUTH_ENCODING
, PROXY_LIST_FILE
: @classmethod
def from_crawler(cls, crawler):
auth_encoding = crawler.settings.get("HTTPPROXY_AUTH_ENCODING", "latin-1")
proxy_list_file = crawler.settings.get("PROXY_LIST_FILE")
return cls(auth_encoding, proxy_list_file)
_set_proxy
方法,根據請求的協定從proxies
中選出一個proxy
給request.meta["proxy"]
: def _set_proxy(self, request, scheme):
creds, proxy = random.choice(self.proxies[scheme])
request.meta["proxy"] = proxy
if creds:
request.headers["Proxy-Authorization"] = b"Basic" + creds
settings.py
中的DOWNLOADER_MIDDLEWARES
,啟用RandomProxyMiddleware
:DOWNLOADER_MIDDLEWARES = {
'get_proxy.middlewares.RandomProxyMiddleware':745
}
PROXY_LIST_FILE
, HTTPPROXY_AUTH_ENCODING
。這樣就完成了,接下來要來實際測試是否可行了,建立一隻簡單的spider
,請求網址為之前測試的網址:
import scrapy
class ProxyExampleSpider(scrapy.Spider):
name = "test"
# start_urls = ['https://httpbin.org/ip']
def start_requests(self):
for i in range(10):
yield scrapy.Request('https://httpbin.org/ip', dont_filter=True)
def parse(self, response):
print(response.text)
好的,接續昨天的主題,今天實作了隨機代理,
其實到目前為止其實已經理解了大部分爬蟲會用到的功能。
最後幾天會再看看有什麼需要說明的吧。
總之今天先這樣了,明天見!
請問 HttpProxyMiddleware 在如果該代理伺服器是不 work 的時候,會自動排除掉下次不再使用嗎?
每次 scrapy crawl XXX 的時候 , 並不會參考上次run spider的所有結果 , 且代理伺服器 是在 middleware中去寫判斷拿取ip並代理
如果 要自動排除掉下次不再使用 , 可以改寫以下方法 , 並寫在pipeline裡
def drop_href(self, item, spider):
if 'nike' in str(item['Brand']):
file_name = spider.settings.get('NIKE_PRODCUTS_JSON_FILE_PATH')
elif 'athleta' in str(item['Brand']):
file_name = spider.settings.get('ATHLETA_PRODUCTS_LINK_PATH')
else:
pass
f = open(file_name, 'r',encoding="utf-8")
a = f.readlines()
f = open(file_name,'w',encoding="utf-8")
for i in a:
f.write(i.replace(str(item['Url']),''))